Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ


Displaying Rendered β€’ View raw β€’ Download

feature/widget/README.md bf929c20f274232e0eb8ddc19b2dc82403e99e5b (bf929c20) Text, 5.62 KB

T383838:feature:widget

Overview

The T383838:feature:widget module is an Android-only Jetpack Glance home-screen widget (API 26+). It exposes a single widget β€” T383838LocalStatsWidget β€” that displays live mesh statistics sourced from the running Meshtastic service.

Target: Android only (not KMP β€” uses T383838meshtastic.android.library + T383838meshtastic.android.library.compose convention plugins)

Key Responsibilities

β€’ Display live mesh statistics on the Android home screen via Jetpack Glance
β€’ Combine four reactive data sources into a single T383838StateFlow<LocalStatsWidgetUiState> for efficient re-renders
β€’ Support three responsive widget sizes: small square, wide rectangle, and large square
β€’ Fulfil the T383838AppWidgetUpdater interface from T383838:core:repository so the mesh service can trigger widget refreshes without depending on Android widget APIs

Source Structure

T282828
src/main/kotlin/org/meshtastic/feature/widget/
β”œβ”€β”€ LocalStatsWidget.kt ← GlanceAppWidget, 3 responsive sizes
β”œβ”€β”€ LocalStatsWidgetReceiver.kt ← GlanceAppWidgetReceiver
β”œβ”€β”€ LocalStatsWidgetState.kt ← LocalStatsWidgetUiState + StateProvider
β”œβ”€β”€ AndroidAppWidgetUpdater.kt ← implements AppWidgetUpdater (core:repository)
β”œβ”€β”€ RefreshLocalStatsAction.kt ← GlanceActionCallback (refresh button)
└── di/
└── FeatureWidgetModule.kt

Widget Content

The widget shows the following information when connected:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Section β”‚ Data shown β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Node identity β”‚ Short name chip with node colours β”‚
β”‚ Battery β”‚ Level percentage + progress bar β”‚
β”‚ Channel utilization β”‚ Percentage + progress bar β”‚
β”‚ Air utilization β”‚ Percentage + progress bar β”‚
β”‚ Traffic β”‚ TX / RX packet counts, duplicates, relay TX, relay cancelled, dropped, ba… β”‚
β”‚ Diagnostics β”‚ Noise floor (dBm), free heap / total heap β”‚
β”‚ Footer β”‚ Online nodes / total nodes, device uptime, last-updated timestamp β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

When disconnected, the widget shows a "Not Connected" state with the last-known node name.

Key Types

T383838LocalStatsWidgetUiState

T282828
Tff7b72data Tff7b72class T56d364LocalStatsWidgetUiStateTb4b4b4(
Tff7b72val Te6edf3connectionStateTb4b4b4: Te6edf3ConnectionStateTb4b4b4,
Tff7b72val Te6edf3isConnectingTb4b4b4: Tffa657BooleanTb4b4b4,
Tff7b72val Te6edf3showContentTb4b4b4: Tffa657BooleanTb4b4b4,
T8b949e// Node identity
Tff7b72val Te6edf3nodeShortNameTb4b4b4: Tffa657String?Tb4b4b4,
Tff7b72val Te6edf3nodeColorsTb4b4b4: Te6edf3PairTff7b72<Tffa657IntTb4b4b4, Tffa657IntTff7b72>Tff7b72?Tb4b4b4,
T8b949e// Battery
Tff7b72val Te6edf3batteryLevelTb4b4b4: Tffa657Int?Tb4b4b4,
Tff7b72val Te6edf3hasBatteryTb4b4b4: Tffa657BooleanTb4b4b4,
T8b949e// Utilization
Tff7b72val Te6edf3channelUtilizationTb4b4b4: Tffa657FloatTb4b4b4,
Tff7b72val Te6edf3airUtilizationTb4b4b4: Tffa657FloatTb4b4b4,
T8b949e// Traffic counters
Tff7b72val Te6edf3numPacketsTxTb4b4b4: Tffa657IntTb4b4b4, Tff7b72val Te6edf3numPacketsRxTb4b4b4: Tffa657IntTb4b4b4,
Tff7b72val Te6edf3numRxDupeTb4b4b4: Tffa657IntTb4b4b4, Tff7b72val Te6edf3numTxRelayTb4b4b4: Tffa657IntTb4b4b4, Tff7b72val Te6edf3numTxRelayCanceledTb4b4b4: Tffa657IntTb4b4b4,
Tff7b72val Te6edf3numTxDroppedTb4b4b4: Tffa657IntTb4b4b4, Tff7b72val Te6edf3numPacketsRxBadTb4b4b4: Tffa657IntTb4b4b4,
T8b949e// Diagnostics
Tff7b72val Te6edf3noiseFloorTb4b4b4: Tffa657Int?Tb4b4b4,
Tff7b72val Te6edf3heapFreeBytesTb4b4b4: Tffa657LongTb4b4b4, Tff7b72val Te6edf3heapTotalBytesTb4b4b4: Tffa657LongTb4b4b4,
T8b949e// Footer
Tff7b72val Te6edf3totalNodesTb4b4b4: Tffa657IntTb4b4b4, Tff7b72val Te6edf3onlineNodesTb4b4b4: Tffa657IntTb4b4b4,
Tff7b72val Te6edf3uptimeSecsTb4b4b4: Tffa657Int?Tb4b4b4,
Tff7b72val Te6edf3updateTimeMillisTb4b4b4: Tffa657LongTb4b4b4,
Tb4b4b4)


T383838LocalStatsWidgetStateProvider

Koin T383838@Single that eagerly combines four repository flows:
β€’ T383838ServiceRepository.connectionState
β€’ T383838NodeRepository.nodeDBbyNum (online/total counts)
β€’ T383838NodeRepository.localStats
β€’ T383838NodeRepository.ourNodeInfo

T282828
Tff7b72val Te6edf3stateTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3LocalStatsWidgetUiStateTff7b72>


T383838LocalStatsWidget

T282828
Tff7b72class T56d364LocalStatsWidget Tb4b4b4: Te6edf3GlanceAppWidgetTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3KoinComponent Tb4b4b4{
Tff7b72override Tff7b72val Te6edf3sizeMode Tff7b72= Te6edf3SizeModeTb4b4b4.Te6edf3ResponsiveTb4b4b4(
Te6edf3setOfTb4b4b4(Te6edf3DpSizeTb4b4b4(T79c0ff1T79c0ff0T79c0ff0.Te6edf3dpTb4b4b4, T79c0ff1T79c0ff0T79c0ff0.Te6edf3dpTb4b4b4)Tb4b4b4, Te6edf3DpSizeTb4b4b4(T79c0ff2T79c0ff5T79c0ff0.Te6edf3dpTb4b4b4, T79c0ff1T79c0ff0T79c0ff0.Te6edf3dpTb4b4b4)Tb4b4b4, Te6edf3DpSizeTb4b4b4(T79c0ff2T79c0ff5T79c0ff0.Te6edf3dpTb4b4b4, T79c0ff2T79c0ff5T79c0ff0.Te6edf3dpTb4b4b4)Tb4b4b4)
Tb4b4b4)
Tb4b4b4}


Tapping the widget opens the app. The refresh button fires T383838RefreshLocalStatsAction, which calls T383838AppWidgetUpdater.updateAll().

T383838AppWidgetUpdater integration

The mesh service holds a reference to T383838AppWidgetUpdater (defined in T383838:core:repository) without depending on Android widget APIs. T383838AndroidAppWidgetUpdater in this module provides the concrete implementation:

T282828
Tff7b72class T56d364AndroidAppWidgetUpdater Tb4b4b4: Te6edf3AppWidgetUpdater Tb4b4b4{
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffupdateAllTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3LocalStatsWidgetTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3updateAllTb4b4b4(Te6edf3contextTb4b4b4)
Tb4b4b4}
Tb4b4b4}


This keeps the service layer platform-agnostic while still enabling widget refresh on data changes.

Dependency Graph

T282828
feature:widget (Android only)
β”œβ”€β”€ core:common, core:model, core:resources, core:repository
β”œβ”€β”€ androidx.glance.appwidget, glance.material3, glance.preview
└── compose.multiplatform.ui (LocalConfiguration, LocalDensity)

Dependency Graph

<!--region graph-->
T282828
Te6edf3graph Te6edf3TB
:Te6edf3featureTb4b4b4:Te6edf3widgetTff7b72[Te6edf3widgetTff7b72]Tff7b72:::Te6edf3androidTff7b72-Te6edf3feature
:Te6edf3featureTb4b4b4:Te6edf3widget Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3common
:Te6edf3featureTb4b4b4:Te6edf3widget Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3model
:Te6edf3featureTb4b4b4:Te6edf3widget Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3resources
:Te6edf3featureTb4b4b4:Te6edf3widget Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3repository

Te6edf3classDef Te6edf3androidTff7b72-Te6edf3application Te6edf3fillTb4b4b4:Te6edf3#CAFFBFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3applicationTff7b72-Te6edf3compose Te6edf3fillTb4b4b4:Te6edf3#CAFFBFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3composeTff7b72-Te6edf3desktopTff7b72-Te6edf3application Te6edf3fillTb4b4b4:Te6edf3#CAFFBFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3feature Te6edf3fillTb4b4b4:Te6edf3#FFD6A5Tb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3library Te6edf3fillTb4b4b4:Te6edf3#9BF6FFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3libraryTff7b72-Te6edf3compose Te6edf3fillTb4b4b4:Te6edf3#9BF6FFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3test Te6edf3fillTb4b4b4:Te6edf3#A0C4FFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3jvmTff7b72-Te6edf3library Te6edf3fillTb4b4b4:Te6edf3#BDB2FFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3kmpTff7b72-Te6edf3feature Te6edf3fillTb4b4b4:Te6edf3#FFD6A5Tb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3kmpTff7b72-Te6edf3libraryTff7b72-Te6edf3compose Te6edf3fillTb4b4b4:Te6edf3#FFC1CCTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3kmpTff7b72-Te6edf3library Te6edf3fillTb4b4b4:Te6edf3#FFC1CCTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Tff7b72unknown Te6edf3fillTb4b4b4:Te6edf3#FFADADTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;


<!--endregion-->

Served by rngit 1.5.0 - Generated in 0.06s